home *** CD-ROM | disk | FTP | other *** search
Wrap
// AmiVNC - Amiga experimental VNC server - Protocol ORL version 3.3 // Includes *********************************************** // Needed to compile : SDK Cybergraphx 4.1 & SDK AmiTCP 4.3 #include <exec/types.h> #include <exec/memory.h> #include <devices/input.h> #include <devices/inputevent.h> #include <libraries/commodities.h> #include <proto/all.h> #include <proto/socket.h> #include <dos.h> #ifndef PLANAR #include <cybergraphx/cybergraphics.h> #include <proto/cybergraphics.h> #endif #include <dos/dostags.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <netdb.h> #include <intuition/intuitionbase.h> #include <intuition/intuition.h> #include <graphics/displayinfo.h> #include <graphics/gfxbase.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <ctype.h> // Specific Includes *********************************************** #include "rfbproto.h" // Structures & constants for VNC protocol #include "vncauth.h" // Prototypes for authentication // Constants *********************************************** #define FALSE 0 // What's that ? #define TRUE 1 // And this ? #define XDC_PORT 5900 // Port # for bind() #define XDC_TILE 32 // Tile size #define XDC_C_VBUF (1L << 0) // Bitmask for pBuffer allocation #define XDC_C_MSOCK (1L << 1) // Bitmask for listen socket open #define XDC_C_CSOCK (1L << 2) // Bitmask for client socket open #define XDC_C_MAXDEPTH 4 // Max. raster depth : 4 bytes / pixel #define XDC_LOGFILE "T:AmiVNC.log" // Log file name #undef PARANO // Common messages char XDC_ID[] = "AmiVNC 0.0.15 Aug 23 1999 (VVA support)"; char XDC_SEND[] = "main.c / main : send() error"; char XDC_RECV[] = "main.c / main : recv() error"; // Global variables *********************************************** LONG iDuplicateSocketKey; // Client socket key for transmitting to child process ULONG uOpened = NULL; // Opened resources, to be closed on exit BOOL bDie = FALSE, *pDie = &bDie; // TRUE : processes are to exit (Argh, very trashy) BOOL bSession = FALSE; // TRUE : clientsession opened char cPassword[MAXPWLEN + 1], // Password *pPreStart = NULL, // User command to execute when connection accepted *pPostStop = NULL; // User command to execute when session closes LONG iMasterSocket, // Listening socket for incoming connections iClientSocket; // Client socket accept()ed UBYTE *pBuffer = NULL, // Reference buffer for screen change detection *P2CBuffer = NULL; // Temp buffer for ReadPixelArray8() in planar2chunky char *sPWFile = "S:AmiVNC.pwd"; // Password file name FILE *fLog = stdout; // Logfile struct sockaddr_in cliAddr; // To find client IP address. Must be addressable for getpeername. struct BitMap *pBM = NULL; // Temp. BitMap for temp. RastPort for p2c // Free all resources allocated to a client session *********************************************** void vCleanSession(char *cMsg, long lCode) { // Tell the child process to exit (as we are the main process, // we can use bDie, which is in our address space) if (!bDie) { bDie = TRUE; Delay(125); } // Close everything opened if (uOpened & XDC_C_VBUF) { free(pBuffer); pBuffer = NULL; uOpened ^= XDC_C_VBUF; } if (pBM) { FreeBitMap(pBM); pBM = NULL; } if (P2CBuffer) { free(P2CBuffer); ; P2CBuffer = NULL; } if (uOpened & XDC_C_CSOCK) { CloseSocket(iClientSocket); uOpened ^= XDC_C_CSOCK; // Execute post-close user command (if any) if (bSession && pPostStop) { char cCommand[128]; sprintf(cCommand, pPostStop, inet_ntoa(cliAddr.sin_addr)); SystemTags(cCommand, SYS_Asynch, TRUE, TAG_DONE); bSession = FALSE; } } fprintf(fLog, "AmiVNC - %s (%ld)\nAmiVNC session closed\n", cMsg, lCode); } // Free all resources allocated to main process and exit *********************************************** void vCleanExit(char *cMsg, long lCode) { // Free tooltype ArgArray initialized by ArgArrayInit() // ArgArrayDone(); vCleanSession(cMsg, lCode); if (uOpened & XDC_C_MSOCK) { CloseSocket(iMasterSocket); uOpened ^= XDC_C_MSOCK; } fprintf(fLog, "AmiVNC halted\n"); if (fLog != stdout) fclose(fLog); exit(0L); } // Handle CTRL-C : do nothing. Will anyways abort blocking socket calls with error, thus provoke exit. void __regargs _CXBRK(void) { } // Authentication *********************************************** BOOL bAuthentify(void) { char cChallenge[16], cResponse[16]; CARD32 c32Value; BOOL bAuthenticated = TRUE; int iCnt, iFile; // Read encoded password in s:AmiVNC.pwd if (!(iFile = open(sPWFile, O_RDONLY, 0))) return(FALSE); iCnt = read(iFile, cPassword, sizeof(cPassword)); close(iFile); if (iCnt != sizeof(cPassword)) return(FALSE); // Decode password vncDecryptPasswd(cPassword, cPassword); // Authenticate the connection, if required if (!strlen(cPassword)) { // Send no-auth-required message c32Value = rfbNoAuth; if (!(-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0)))) return FALSE; return(TRUE); } else { // Send auth-required message c32Value = rfbVncAuth; if (-1 == (send(iClientSocket,(char *)&c32Value, sizeof(c32Value), 0))) return FALSE; // Now create a 16-byte challenge vncRandomBytes((BYTE *)cChallenge); // Send the challenge to the client if (-1 == (send(iClientSocket, cChallenge, sizeof(cChallenge), 0))) return FALSE; // Read the response if (-1 == (recv(iClientSocket, cResponse, sizeof(cResponse), 0))) return FALSE; // Encrypt the challenge bytes vncEncryptBytes((BYTE *)cChallenge, cPassword); // Compare them to the response for (iCnt = 0; iCnt < sizeof(cChallenge); iCnt++) { if (cChallenge[iCnt] != cResponse[iCnt]) { bAuthenticated = FALSE; break; } } // Did the authentication work? if (!bAuthenticated) { c32Value = rfbVncAuthFailed; send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0); return FALSE; } else { // Tell the client we're ok c32Value = rfbVncAuthOK; if (-1 == (send(iClientSocket, (char *)&c32Value, sizeof(c32Value), 0))) return FALSE; return(TRUE); } } } // Incoming messages management thread *********************************************** void __saveds vProcessIncomes(void) { struct IOStdReq *inputReqBlk; struct MsgPort *inputPort; struct InputEvent eEvent, *VNCEvent = &eEvent; UWORD uQualifier = 0; rfbClientToServerMsg sCMsg; BOOL bLClick = FALSE, bMClick = FALSE, bRClick = FALSE; struct Library *SocketBase; LONG iSocketChild; // We have to reopen bsdsocket.library, because it can not be shared between processes // OpenLibrary can not fail since it would have halted the father before creating us. SocketBase = OpenLibrary("bsdsocket.library", 4L); // Obtain the client socket descriptor from the key saved for us by our father if (-1 == (iSocketChild = ObtainSocket(iDuplicateSocketKey, AF_INET, SOCK_STREAM, 0))) { fprintf(fLog, "main.c / vProcessIncomes : ObtainSocket() error %d\n", Errno()); *pDie = TRUE; goto _Nosock; } fprintf(fLog, "main.c / vProcessIncomes runs on socket %d\n", iSocketChild); // Create input.device message structure inputPort = CreatePort(NULL, NULL); inputReqBlk = (struct IOStdReq *) CreateExtIO(inputPort, sizeof(struct IOStdReq)); OpenDevice("input.device", NULL, (struct IORequest *) inputReqBlk, NULL); inputReqBlk -> io_Data = (APTR) VNCEvent; inputReqBlk -> io_Command = IND_WRITEEVENT; inputReqBlk -> io_Flags = 0; inputReqBlk -> io_Length = sizeof(struct InputEvent); // Process incoming messages until main process tells to die. // Use pointer to bDie because it is not in our address space... while (!*pDie) // VERY VERY dirty way to know we have to exit... { if (-1 == recv(iSocketChild, (UBYTE *) &sCMsg, 1, 0)) { fprintf(fLog, "main.c / vProcessIncomes : recv() error, errno = %d\n", Errno()); *pDie = TRUE; continue; } Forbid(); // Leave us handle properly our input event switch(sCMsg.type) { case rfbSetPixelFormat : // 0 if (sz_rfbSetPixelFormatMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetPixelFormatMsg - 1, 0)) { #ifdef PARANO printf("C -> S : rfbSetPixelFormat lanbpp %d depth %d bigE %d tc %d redM %d redS %d GreM %d GreS %d BluM %d BluS %d\n", sCMsg.spf.format.bitsPerPixel, sCMsg.spf.format.depth, sCMsg.spf.format.bigEndian, sCMsg.spf.format.trueColour, sCMsg.spf.format.redMax, sCMsg.spf.format.redShift, sCMsg.spf.format.greenMax, sCMsg.spf.format.greenShift, sCMsg.spf.format.blueMax, sCMsg.spf.format.blueShift ); #endif // PARANO break; } case rfbFixColourMapEntries : // 1 if (sz_rfbFixColourMapEntriesMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFixColourMapEntriesMsg - 1, 0)) { #ifdef PARANO printf("C -> S : rfbFixColourMapEntries\n"); #endif // PARANO break; } case rfbSetEncodings : // 2 if (sz_rfbSetEncodingsMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbSetEncodingsMsg - 1, 0)) { #ifdef PARANO printf("C -> S : rfbSetEncodings\n"); #endif // PARANO break; } case rfbFramebufferUpdateRequest : // 3 if (sz_rfbFramebufferUpdateRequestMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbFramebufferUpdateRequestMsg - 1, 0)) { #ifdef PARANO printf("C -> S : rfbFramebufferUpdateRequest inc %d x %d y %d w %d h %d\n", sCMsg.fur.incremental, sCMsg.fur.x, sCMsg.fur.y, sCMsg.fur.w, sCMsg.fur.h ); #endif // PARANO break; } case rfbKeyEvent : // 4 if (sz_rfbKeyEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbKeyEventMsg - 1, 0)) { #ifdef PARANO printf("C -> S : rfbKeyEvent down %d key %d ('%c')\n", sCMsg.ke.down, sCMsg.ke.key, sCMsg.ke.key ); #endif // PARANO // Process special keys if ((sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0))) { if (sCMsg.ke.key == 0xFFE1) uQualifier |= IEQUALIFIER_LSHIFT; // Left Shift if (sCMsg.ke.key == 0xFFE2) uQualifier |= IEQUALIFIER_RSHIFT; // Right Shift if (sCMsg.ke.key == 0xFFE3) uQualifier |= IEQUALIFIER_CONTROL; // Left Control if (sCMsg.ke.key == 0xFFE4) uQualifier |= IEQUALIFIER_CONTROL; // Right Control if (sCMsg.ke.key == 0xFFE9) uQualifier |= IEQUALIFIER_LALT; // Left Alt if (sCMsg.ke.key == 0xFFEA) uQualifier |= IEQUALIFIER_RALT; // Right Alt break; } if ((!sCMsg.ke.down) && (0xFFE0 == (sCMsg.ke.key & 0xFFE0))) { if (sCMsg.ke.key == 0xFFE1) uQualifier &= ~IEQUALIFIER_LSHIFT; // Left Shift if (sCMsg.ke.key == 0xFFE2) uQualifier &= ~IEQUALIFIER_RSHIFT; // Right Shift if (sCMsg.ke.key == 0xFFE3) uQualifier &= ~IEQUALIFIER_CONTROL; // Left Control if (sCMsg.ke.key == 0xFFE4) uQualifier &= ~IEQUALIFIER_CONTROL; // Right Control if (sCMsg.ke.key == 0xFFE9) uQualifier &= ~IEQUALIFIER_LALT; // Left Alt if (sCMsg.ke.key == 0xFFEA) uQualifier &= ~IEQUALIFIER_RALT; // Right Alt break; } // Do nothing on key release if (!sCMsg.ke.down) break; // Process cursor-related keys if (0xFF50 == (sCMsg.ke.key & 0xFF50)) { VNCEvent -> ie_Class = IECLASS_RAWKEY; VNCEvent -> ie_Qualifier = 0; switch(sCMsg.ke.key & 0x000F) { case 0 : // Home VNCEvent -> ie_Code = 0x3D; break; case 1 : // Left VNCEvent -> ie_Code = 0x4F; break; case 2 : // Up VNCEvent -> ie_Code = 0x4C; break; case 3 : // Right VNCEvent -> ie_Code = 0x4E; break; case 4 : // Down VNCEvent -> ie_Code = 0x4D; break; case 5 : // Page up VNCEvent -> ie_Code = 0x3F; break; case 6 : // Page down VNCEvent -> ie_Code = 0x1F; break; case 7 : // End VNCEvent -> ie_Code = 0x1D; break; default : break; } } else { // Map out other 0xFF'ed keys sCMsg.ke.key &= 0xFF; // Find rawkey event out of key ; if we can not, reject key if (!InvertKeyMap((ULONG) sCMsg.ke.key, VNCEvent, NULL)) break; } // Apply qualifier if possible if (!strchr("~`£µ¨89", (int) sCMsg.ke.key)) switch(uQualifier) { case IEQUALIFIER_CONTROL : case IEQUALIFIER_LSHIFT : case IEQUALIFIER_RSHIFT : VNCEvent -> ie_Qualifier = uQualifier; break; case IEQUALIFIER_LALT : VNCEvent -> ie_Qualifier = IEQUALIFIER_LCOMMAND; break; case IEQUALIFIER_RALT | IEQUALIFIER_CONTROL : VNCEvent -> ie_Qualifier = IEQUALIFIER_RCOMMAND; break; } // Send key into input.device DoIO((struct IORequest *) inputReqBlk); break; } case rfbPointerEvent : // 5 if (sz_rfbPointerEventMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbPointerEventMsg - 1, 0)) { #ifdef PARANO printf("C -> S : rfbPointerEvent button %d x %d y %d\r", sCMsg.pe.buttonMask, sCMsg.pe.x, sCMsg.pe.y ); #endif // PARANO VNCEvent -> ie_NextEvent = NULL; VNCEvent -> ie_Class = IECLASS_POINTERPOS; VNCEvent -> ie_Qualifier = uQualifier; // Process mouse X & Y VNCEvent -> ie_X = sCMsg.pe.x; VNCEvent -> ie_Y = sCMsg.pe.y; // Process mouse buttons... VNCEvent -> ie_Code = IECODE_NOBUTTON; // Left button if ((sCMsg.pe.buttonMask) & 1) { if (bLClick) VNCEvent -> ie_Code = IECODE_NOBUTTON; else { bLClick = TRUE; VNCEvent -> ie_Code = IECODE_LBUTTON; uQualifier |= IEQUALIFIER_LEFTBUTTON; } } else if (bLClick) { bLClick = FALSE; VNCEvent -> ie_Code = IECODE_LBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_LEFTBUTTON; } // Middle button if ((sCMsg.pe.buttonMask) & 2) { if (bMClick) VNCEvent -> ie_Code = IECODE_NOBUTTON; else { bMClick = TRUE; VNCEvent -> ie_Code = IECODE_MBUTTON; uQualifier |= IEQUALIFIER_MIDBUTTON; } } else if (bMClick) { bMClick = FALSE; VNCEvent -> ie_Code = IECODE_MBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_MIDBUTTON; } // Right button if ((sCMsg.pe.buttonMask) & 4) { if (bRClick) VNCEvent -> ie_Code = IECODE_NOBUTTON; else { bRClick = TRUE; VNCEvent -> ie_Code = IECODE_RBUTTON; uQualifier |= IEQUALIFIER_RBUTTON; } } else if (bRClick) { bRClick = FALSE; VNCEvent -> ie_Code = IECODE_RBUTTON | IECODE_UP_PREFIX; uQualifier &= ~IEQUALIFIER_RBUTTON; } // Insert event into input.device stream DoIO((struct IORequest *) inputReqBlk); break; } case rfbClientCutText : // 6 if (sz_rfbClientCutTextMsg - 1 == recv(iSocketChild, 1 + (UBYTE *) & sCMsg, sz_rfbClientCutTextMsg - 1, 0)) { char *cText = malloc((size_t) (sCMsg.cct.length + 1)); recv(iSocketChild, cText, sCMsg.cct.length, 0); cText[sCMsg.cct.length] = 0; #ifdef PARANO printf("C -> S : rfbClientCutText '%s'\n", cText); #endif // PARANO break; } default : #ifdef PARANO printf("main.c / vProcessIncomes : msg type %d unknown\n", sCMsg.type); #endif // PARANO break; } Permit(); } CloseSocket(iSocketChild); if (inputReqBlk) { CloseDevice((struct IORequest *) inputReqBlk); DeleteExtIO((struct IORequest *) inputReqBlk); } if (inputPort) DeletePort(inputPort); _Nosock: CloseLibrary(SocketBase); fprintf(fLog, "main.c / vProcessIncomes halted\n"); } // Main entry point *********************************************** int main(int argc, char **argv) { register int iCnt, jCnt; BPTR pFile; int iMajor, iMinor, iWidth, iHeight, iDepth, iSize, iMode, iPort, iUpdate = 0, iRShift = 8, iGShift = 16, iBShift = 24; unsigned long uLimit = 0xFFFFFFFF, uSize, uCnt; struct sockaddr_in sAddr; // Local address for bind() struct Screen *pActiveScreen; rfbProtocolVersionMsg mProtVerMsg; rfbServerInitMsg mSerInitMsg; rfbFramebufferUpdateMsg mFBUpdMsg; rfbFramebufferUpdateRectHeader mFBRMsg; CARD8 c8; BOOL bBig = FALSE, bFastMode, bPlanar, bVVA = FALSE; register UBYTE *pRaster; // True WB screen raster static UBYTE uTile[XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH]; // 3 Byte/pixel RGB Raster tile for client screen updates static UBYTE uCTile[XDC_TILE * XDC_TILE]; // Chunky tile for planar comparisons char cLog[80], *pC, **ArgArray; UWORD CLUT[256]; // 16 bit Planar2Chunky color lookup table (pen number -> RGB16PC values) UBYTE CLUT8[256]; // 8 bit Planar2Chunky color lookup table (pen number -> BGR233 values) struct RastPort TempRP; // Temp. RastPort for ReadPixelArray8 #ifndef PLANAR struct Library *CGXlib = OpenLibrary("cgxsystem.library", 40L); #endif iPort = XDC_PORT; strcpy(cLog, XDC_LOGFILE); // Process AmiVNC icon tooltypes ArgArray = ArgArrayInit((long) argc, argv); if (pC = FindToolType(ArgArray, "PORT")) iPort = atoi(pC); if (pC = FindToolType(ArgArray, "BIGENDIAN")) bBig = (tolower(*pC) == 't') ? TRUE : FALSE; if ((pC = FindToolType(ArgArray, "LIMIT")) && (atoi(pC))) uLimit = atoi(pC); if (pC = FindToolType(ArgArray, "RSHIFT")) iRShift = atoi(pC); if (pC = FindToolType(ArgArray, "GSHIFT")) iGShift = atoi(pC); if (pC = FindToolType(ArgArray, "BSHIFT")) iBShift = atoi(pC); if (pC = FindToolType(ArgArray, "LOGFILE")) strcpy(cLog, pC); if (pC = FindToolType(ArgArray, "PRESTART")) pPreStart = pC; if (pC = FindToolType(ArgArray, "POSTSTOP")) pPostStop = pC; if (pC = FindToolType(ArgArray, "VERBOSE")) cLog[0] = 0; if (pC = FindToolType(ArgArray, "VVA")) bVVA = TRUE; // Process command line arguments (if any) if (argc > 1) while (*++argv) { switch(tolower((*argv)[1])) { // *** Print usage case '?' : case 'h' : printf("Options :\n -p<pwd> to store password\n"); printf(" -s<port> to set listen port (default %d)\n", XDC_PORT); printf(" -e to force big endian (default little)\n"); printf(" -l<size> to limit net block size (default unlimited\n"); printf(" -(r|g|b)<value> to force color encoding r|g|b bitshift (defaults 8|16|24)\n"); vCleanExit("main.c / main : stopping...", 0); break; // *** Force password change and exit case 'p' : strncpy(cPassword, *argv + 2, MAXPWLEN); cPassword[MAXPWLEN] = '\0'; pC = strchr(cPassword, ' '); if (pC) *pC = '\0'; for (iCnt = strlen(cPassword) ; iCnt < MAXPWLEN ; iCnt++) cPassword[iCnt] = '\0'; vncEncryptPasswd(cPassword, cPassword); if (!(pFile = Open(sPWFile, MODE_NEWFILE))) vCleanExit("main.c / main : creat('s:AmiVNC.pwd') error", 0); Write(pFile, cPassword, sizeof(cPassword)); Close(pFile); vCleanExit("main.c / main : Passwd stored", 0); break; // *** Force another port than the default 5900 case 's' : iPort = atoi(*argv + 2); break; // *** Force BigEndian flag in mSerInitMsg case 'e' : bBig = TRUE; break; // *** Limit netblocksize for initial screen update case 'l' : uLimit = atoi(*argv + 2); break; // *** Force Red / Green / Blue bitshifts in mSerInitMsg // (play with this if you have color problems, legal values // for shifts are 0, 8, 16 and 24) case 'r' : iRShift = atoi(*argv + 2); break; case 'g' : iGShift = atoi(*argv + 2); break; case 'b' : iBShift = atoi(*argv + 2); break; // Force verbose mode to sdtout case 'v' : cLog[0] = 0; break; // Force VVA compatible (BGR233) pixel encoding case 'a' : bVVA = TRUE; break; default : printf("main.c / main : Arg [%s] ignored\n", *argv); break; } } // If log not forced to stdout, open log file if (cLog[0]) { fLog = fopen(cLog, "wt"); if (!fLog) { fLog = stdout; vCleanExit("main.c / main : Log file error", 0); } } // Welcome... fprintf(fLog, "%s\n(c) 1999 stephane.guillard@steria.fr\n", XDC_ID); // Print configurable parameter values fprintf(fLog, "main.c / main : parameter values :\n"); fprintf(fLog, " - listen port set to %d\n", iPort); fprintf(fLog, " - endian set to %s\n", bBig ? "big" : "little"); fprintf(fLog, " - initial xfer limit set to %08lX\n", uLimit); fprintf(fLog, " - color bitshifts : red %d, green %d, blue %d\n", iRShift, iGShift, iBShift); // Prepare listener socket fprintf(fLog, "main.c / main : Creating listener socket\n"); if (-1 == (iMasterSocket = socket(AF_INET, SOCK_STREAM, 0))) vCleanExit("main.c / main : socket() error", Errno()); uOpened |= XDC_C_MSOCK; sAddr.sin_family=AF_INET; sAddr.sin_addr.s_addr = 0; sAddr.sin_port = htons(iPort); fprintf(fLog, "main.c / main : Binding socket on port %d\n", sAddr.sin_port); if (-1 == (bind(iMasterSocket, (struct sockaddr *) &sAddr, sizeof(sAddr)))) vCleanExit("main.c / main : bind() error", Errno()); fprintf(fLog, "main.c / main : Listening set on port %d\n", sAddr.sin_port); if (-1 == (listen(iMasterSocket, 4))) vCleanExit("main.c / main : listen() error", Errno()); _NewSession: bDie = FALSE; // Wait for incoming connections fprintf(fLog, "main.c / main : Waiting for client connection\n"); if (-1 == (iClientSocket = accept(iMasterSocket, NULL, NULL))) vCleanExit("main.c / main : accept() error", Errno()); uOpened |= XDC_C_CSOCK; // Find client IP address (use iDuplicateSocketKey as temp. var because at this point it is useless) iDuplicateSocketKey = sizeof(cliAddr); getpeername(iClientSocket, (struct sockaddr *) &cliAddr, &iDuplicateSocketKey); fprintf(fLog, "main.c / main : accept()ed connection from %s on socket %d\n", inet_ntoa(cliAddr.sin_addr), iClientSocket); // NegociateProtocolVersion fprintf(fLog, "main.c / main : Negociating protocol version\n"); sprintf((char *) mProtVerMsg, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion); if (-1 == (send(iClientSocket, (UBYTE *) mProtVerMsg, sz_rfbProtocolVersionMsg, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } mProtVerMsg[12] = 0; if (-1 == (recv(iClientSocket, mProtVerMsg, sz_rfbProtocolVersionMsg, 0))) { vCleanSession(XDC_RECV, Errno()); goto _NewSession; } sscanf((char *) mProtVerMsg, rfbProtocolVersionFormat, &iMajor, &iMinor); fprintf(fLog, "main.c / main : Protocol supported by server : %d.%d, by client : %d.%d\n", rfbProtocolMajorVersion, rfbProtocolMinorVersion, iMajor, iMinor); // If major == minor == 0, fake client asks us to exit if ((!iMajor) && (!iMinor)) vCleanExit("main.c / main : Exit asked", 0); // Check protocol version if (iMajor > rfbProtocolMajorVersion) { vCleanSession("main.c / main : unknown protocol", 0); goto _NewSession; } // Authenticate DES fprintf(fLog, "main.c / main : Authentication\n"); if (FALSE == bAuthentify()) { vCleanSession("main.c / main : Authenticate error", 0); goto _NewSession; } // ClientInit fprintf(fLog, "main.c / main : ClientInitialisation\n"); if (-1 == (recv(iClientSocket, &c8, sizeof(c8), 0))) { vCleanSession(XDC_RECV, Errno()); goto _NewSession; } fprintf(fLog, "main.c / main : SharedFlag = %d (multiple clients : %s)\n", c8, c8 ? "Yes" : "No"); // Grab active screen pActiveScreen = IntuitionBase -> FirstScreen; // Check if planar Amiga screen bPlanar = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD ? TRUE : FALSE; fprintf(fLog, "main.c / main : Screen set to [%s] (%s)\n", pActiveScreen -> Title, bPlanar ? "planar" : "RTG"); // Get screen info (mode, width, height, depth, linear address) if (!bPlanar) // RTG chunky linear modes { #ifndef PLANAR if (GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX) && GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM)) { // Get screenmode, width, height, depth iMode = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_PIXFMT); iWidth = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_WIDTH); // X size iHeight = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT); // Y size iDepth = GetCyberMapAttr(pActiveScreen -> RastPort.BitMap, CYBRMATTR_BPPIX); // Depth is in Bytes / pixel // Grab chunky raster pointer (dirty but EFFICIENT !) UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap, LBMI_BASEADDRESS, (ULONG *) &uCnt, TAG_DONE)); pRaster = (UBYTE *) uCnt; // Calculate total byte size of screen raster (adjust to 2 byte / pixel if CLUT, will realloc later) iSize = iWidth * iHeight * (iDepth > 1 ? iDepth : 2); fprintf(fLog, "main.c / main : RTG mode %s/%ld ", CGXlib ? "CGFx" : "Pic96", iMode); } else // mode unsupported (neither planar neither RTG chunky linear) #endif { vCleanSession("main.c / main : screenmode not supported", 0); goto _NewSession; } } else // non-RTG (Amiga Classic chipset planar modes) { // Get width, height, depth iMode = 0xFF; // To remember this is a non-RTG screen to set up frame buffer format for ServerInit iWidth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_WIDTH); // X size iHeight = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_HEIGHT); // Y size iDepth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_DEPTH); // Depth is in Bits / pixel // Force size to 2 X Y (each planar pixel will be sent as a 2 byte RGB4 chunky pixel) iSize = iWidth * iHeight * 2; // Screen memory is not linear addressable (but we rather have a raster per bitplane) pRaster = NULL; fprintf(fLog, "main.c / main : planar mode "); } fprintf(fLog, "@ 0x%08lX, %dx%d, %d %cpp, size %d\n", pRaster, iWidth, iHeight, iDepth, bPlanar ? 'b' : 'B', bPlanar ? iWidth * iHeight * iDepth / 8 : iSize); // Fast mode : 2 byte pixel buffer : // - planar Amiga screens // OR // - Picasso96 AND 2 byte pixels // OR // - 1 byte RTG CLUT pixels #ifndef PLANAR bFastMode = ((bPlanar) || ((!CGXlib) && (iDepth == 2)) || (iDepth == 1)); #else bFastMode = TRUE; #endif // Allocate pBuffer (reference buffer for screen compare) // - with the screen size if no VVA, and ((under P96 and Depth < 3) OR if planar) // - with 4 byte / pixel size if under CGFx or Depth >= 3 or VVA if (!(pBuffer = malloc((!bVVA && bFastMode) ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH))) { vCleanSession("main.c / main : malloc() error", 0); goto _NewSession; } uOpened |= XDC_C_VBUF; // ServerInit : prepare RGB encodings if (bFastMode) { #ifndef PLANAR switch(iMode) { case PIXFMT_RGB16PC : // TESTED OK /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggbbbbbrrrrrggg */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 16; mSerInitMsg.format.bigEndian = TRUE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 63; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 11; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 0; break; case PIXFMT_RGB15PC : /* HiColor15 (5 bit each), format: gggbbbbb0rrrrrgg */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 15; mSerInitMsg.format.bigEndian = TRUE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 31; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 10; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 0; break; case PIXFMT_RGB16 : /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: rrrrrggggggbbbbb */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 16; mSerInitMsg.format.bigEndian = FALSE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 63; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 11; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 0; break; case PIXFMT_RGB15 : /* HiColor15 (5 bit each), format: 0rrrrrgggggbbbbb */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 15; mSerInitMsg.format.bigEndian = FALSE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 31; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 10; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 0; break; case PIXFMT_BGR16PC : /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: gggrrrrrbbbbbggg */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 16; mSerInitMsg.format.bigEndian = TRUE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 63; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 0; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 11; break; case PIXFMT_BGR15PC : /* HiColor15 (5 bit each), format: gggrrrrr0bbbbbbgg */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 15; mSerInitMsg.format.bigEndian = TRUE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 31; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 0; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 10; break; case PIXFMT_BGR16 : /* HiColor16 (5 bit R, 6 bit G, 5 bit B), format: bbbbbggggggrrrrr */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 16; mSerInitMsg.format.bigEndian = FALSE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 63; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 0; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 11; break; case PIXFMT_BGR15 : /* HiColor15 (5 bit each), format: 0bbbbbbgggggrrrrr */ mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 15; mSerInitMsg.format.bigEndian = FALSE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 31; mSerInitMsg.format.greenMax = 31; mSerInitMsg.format.blueMax = 31; mSerInitMsg.format.redShift = 0; mSerInitMsg.format.greenShift = 5; mSerInitMsg.format.blueShift = 10; break; case PIXFMT_LUT8 : /* Chunky CLUT screens, or ... */ case 0xFF : /* planar screens : send 2 byte pixels,aligned as per GetRGB4 : 0000RRRR GGGGBBBB*/ #endif mSerInitMsg.format.bitsPerPixel = 16; mSerInitMsg.format.depth = 12; mSerInitMsg.format.bigEndian = FALSE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 15; mSerInitMsg.format.greenMax = 15; mSerInitMsg.format.blueMax = 15; mSerInitMsg.format.redShift = 8; // 0 mSerInitMsg.format.greenShift = 4; // 12 mSerInitMsg.format.blueShift = 0; // 8 #ifndef PLANAR break; default : { vCleanSession("main.c / main : RGB mode not supported", 0); goto _NewSession; } break; } } else // CGFx or Depth > 2 or screen not planar // then use dumb 24 bpp mode, sent as 32 bpp because VNC protocol forbids 3 byte pixels { mSerInitMsg.format.bitsPerPixel = 32; mSerInitMsg.format.depth = 24; mSerInitMsg.format.bigEndian = bBig; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = mSerInitMsg.format.greenMax = mSerInitMsg.format.blueMax = 255; mSerInitMsg.format.redShift = iRShift; mSerInitMsg.format.greenShift = iGShift; mSerInitMsg.format.blueShift = iBShift; #endif } // if client is VVA, force encoding as BGR233 in all cases, as VVA only knows this encoding if (bVVA) { mSerInitMsg.format.bitsPerPixel = 8; mSerInitMsg.format.depth = 8; mSerInitMsg.format.bigEndian = FALSE; mSerInitMsg.format.trueColour = TRUE; mSerInitMsg.format.redMax = 7; mSerInitMsg.format.greenMax = 7; mSerInitMsg.format.blueMax = 3; mSerInitMsg.format.redShift = 0; mSerInitMsg.format.greenShift = 3; mSerInitMsg.format.blueShift = 6; } // Finish serverinit and send it mSerInitMsg.framebufferWidth = iWidth; mSerInitMsg.framebufferHeight = iHeight; mSerInitMsg.nameLength = sizeof(XDC_ID); if (-1 == (send(iClientSocket, (UBYTE *) &mSerInitMsg, sizeof(mSerInitMsg), 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } if (-1 == (send(iClientSocket, (UBYTE *) XDC_ID, sizeof(XDC_ID), 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } // Initial Screen update : header... mFBUpdMsg.type = rfbFramebufferUpdate; mFBUpdMsg.nRects = 1; if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } // Initial Screen update : 1 rectangle for whole screen... mFBRMsg.r.x = 0; mFBRMsg.r.y = 0; mFBRMsg.r.w = iWidth; mFBRMsg.r.h = iHeight; mFBRMsg.encoding = rfbEncodingRaw; if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } // Copy raster into buffer for send() and for ulterior compares if ((bFastMode) && (!bVVA)) // Planar or Pic96/2 byte pixels, no VVA { if (bPlanar) // planar screen { // We have to : // - ReadPixelArray8 the whole screen, // - make a (256 entries max.) color lookup table (CLUT) out of screen colormap // - Then encode each pixel with GetRGB4 and the CLUT, as a 16 bit pixel array to send to the client P2CBuffer = malloc(iWidth * iHeight); // 1 byte per pixel : pen number // Allocate bitmap for temp. rastport for ReadPixelArray8() pBM = AllocBitMap((unsigned long) iWidth, (unsigned long) 1, (unsigned long) iDepth, BMF_CLEAR | BMF_DISPLAYABLE, pActiveScreen -> RastPort.BitMap); // Temp. BitMap for temp. RastPort // Initialize temporary rastport necessary for ReadPixelArray8() InitRastPort(&TempRP); TempRP.Layer = NULL; TempRP.BitMap = pBM; // Fill color lookup table with ready-to-send 16 bit RGB values jCnt = 1 << iDepth; for (iCnt = 0 ; iCnt < jCnt ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); ULONG wR = (lColor >> 8) & 0x0f; ULONG wG = (lColor >> 4) & 0x0f; ULONG wB = (lColor >> 0) & 0x0f; CLUT[iCnt] = (wG << 4 | wB) << 8 | wR; } // Read our chunky clut-index array from planar raster ReadPixelArray8(&(pActiveScreen -> RastPort), (unsigned long) 0, (unsigned long) 0, (unsigned long) iWidth - 1, (unsigned long) iHeight - 1, P2CBuffer, &TempRP ); // Make up the RBG chunky buffer for (jCnt = 0 ; jCnt < iHeight ; jCnt++) for (iCnt = 0 ; iCnt < iWidth ; iCnt++) *((UWORD *) (pBuffer + (iCnt + jCnt * iWidth) * 2)) = CLUT[P2CBuffer[iCnt + jCnt * iWidth]]; } #ifndef PLANAR else if (iDepth == 1) // 8 bit pixels, CLUT, RTG chunky { // Fill color lookup table with 256 ready-to-send 16 bit RGB values for (iCnt = 0 ; iCnt < 256 ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); ULONG wR = (lColor >> 8) & 0x0f; ULONG wG = (lColor >> 4) & 0x0f; ULONG wB = (lColor >> 0) & 0x0f; CLUT[iCnt] = (wG << 4 | wB) << 8 | wR; } // Make up the RBG chunky buffer for (jCnt = 0 ; jCnt < iHeight ; jCnt++) for (iCnt = 0 ; iCnt < iWidth ; iCnt++) *((UWORD *) (pBuffer + (iCnt + jCnt * iWidth) * 2)) = CLUT[pRaster[iCnt + jCnt * iWidth]]; } else // Picasso 96 2 byte pixel screen { // simply send raster memory (as 16 bit pixels) memcpy(pBuffer, pRaster, iSize); } #endif uSize = uLimit < iSize ? uLimit : iSize; } else // neither planar nor CLUT nor Pic96/2byte pixels (thus 3 or more byte pixels or CGFx > 1 Bpp), or VVA in any case { if (bPlanar) // planar screen { // We have to : // - ReadPixelArray8 the whole screen, // - make a (256 entries max.) color lookup table (CLUT) out of screen colormap // - Then encode each pixel with GetRGB4 and the CLUT, as a 8 bit BGR233 pixel array to send to the client P2CBuffer = malloc(iWidth * iHeight); // 1 byte per pixel : pen number // Allocate bitmap for temp. rastport for ReadPixelArray8() pBM = AllocBitMap((unsigned long) iWidth, (unsigned long) 1, (unsigned long) iDepth, BMF_CLEAR | BMF_DISPLAYABLE, pActiveScreen -> RastPort.BitMap); // Temp. BitMap for temp. RastPort // Initialize temporary rastport necessary for ReadPixelArray8() InitRastPort(&TempRP); TempRP.Layer = NULL; TempRP.BitMap = pBM; // Fill color lookup table with ready-to-send BGR233 values jCnt = 1 << iDepth; for (iCnt = 0 ; iCnt < jCnt ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); UBYTE wR = (lColor >> 9) & 0x07; UBYTE wG = (lColor >> 5) & 0x07; UBYTE wB = (lColor >> 2) & 0x03; CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR; } // Read our chunky clut-index array from planar raster ReadPixelArray8(&(pActiveScreen -> RastPort), (unsigned long) 0, (unsigned long) 0, (unsigned long) iWidth - 1, (unsigned long) iHeight - 1, P2CBuffer, &TempRP ); // Make up the BGR233 chunky buffer for (jCnt = 0 ; jCnt < iHeight ; jCnt++) for (iCnt = 0 ; iCnt < iWidth ; iCnt++) pBuffer[iCnt + jCnt * iWidth] = CLUT8[P2CBuffer[iCnt + jCnt * iWidth]]; uSize = uLimit < iWidth * iHeight ? uLimit : iWidth * iHeight; } #ifndef PLANAR else if (iDepth == 1) // 8 bit pixels, CLUT, RTG chunky { // Fill color lookup table with 256 ready-to-send BGR233 values for (iCnt = 0 ; iCnt < 256 ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); UBYTE wR = (lColor >> 9) & 0x07; UBYTE wG = (lColor >> 5) & 0x07; UBYTE wB = (lColor >> 2) & 0x03; CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR; } // Make up the RBG chunky buffer for (jCnt = 0 ; jCnt < iHeight ; jCnt++) for (iCnt = 0 ; iCnt < iWidth ; iCnt++) pBuffer[iCnt + jCnt * iWidth] = CLUT8[pRaster[iCnt + jCnt * iWidth]]; uSize = uLimit < iWidth * iHeight ? uLimit : iWidth * iHeight; } else // All RTG modes with depth > 1 byte { // We have to make 4 byte pixels out of the raster ReadPixelArray(pBuffer, // Buffer 0, 0, // Dest X/Y in buffer iWidth * XDC_C_MAXDEPTH, // Byte width of buffer &(pActiveScreen -> RastPort), 0, 0, // Source X/Y iWidth, iHeight, // Source w/h RECTFMT_ARGB ); if (bVVA) { // Make up the BGR233 buffer for (jCnt = 0 ; jCnt < iHeight ; jCnt++) for (iCnt = 0 ; iCnt < iWidth ; iCnt++) { pBuffer[iCnt + jCnt * iWidth] = (pBuffer[(iCnt + jCnt * iWidth) * 4 + 1] & 0xE0) >> 5 | (pBuffer[(iCnt + jCnt * iWidth) * 4 + 2] & 0xE0) >> 2 | (pBuffer[(iCnt + jCnt * iWidth) * 4 + 3] & 0xC0) >> 0; } uSize = uLimit < iWidth * iHeight ? uLimit : iWidth * iHeight; } else uSize = uLimit < iWidth * iHeight * XDC_C_MAXDEPTH ? uLimit : iWidth * iHeight * XDC_C_MAXDEPTH; } #endif } // Send buffer (by uLimit packet size if set). uCnt = 0; while (uCnt < (bVVA ? iWidth * iHeight : ((bFastMode) ? iSize : iWidth * iHeight * XDC_C_MAXDEPTH))) { if (-1 == (send(iClientSocket, (UBYTE *) pBuffer + uCnt, uSize, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } uCnt += uSize; } #ifndef PLANAR // if CGFx or depth > 2, reallocate the buffer to actual raster size (eg .3 byte / pixel instead of 4) if (!bFastMode) { // Reallocate the buffer, resizing it to what's really necessary if (!(pBuffer = realloc(pBuffer, iWidth * iHeight * (CGXlib ? iDepth : ((iDepth != 3) ? iDepth : 4))))) { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; } // Byte copy the screen into the buffer for fast compare memcpy(pBuffer, pRaster, iSize); } #endif // if planar, reallocate the buffer to iWidth x iDepth for ReadPixelArray8() and store chunky raster if (bPlanar) { // Reallocate the buffer, resizing it to what's really necessary if (!(pBuffer = realloc(pBuffer, iWidth * iHeight))) { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; } // Byte copy the screen into the buffer for fast compare memcpy(pBuffer, P2CBuffer, iWidth * iHeight); // Free P2CBuffer, which from now on is useless free(P2CBuffer); P2CBuffer = NULL; } #ifndef PLANAR // if RTG chunky CLUT, reallocate the buffer to iWidth x iDepth and copy screen raster into it if ((!bPlanar) && (iDepth == 1)) { // Reallocate the buffer, resizing it to what's really necessary if (!(pBuffer = realloc(pBuffer, iWidth * iHeight))) { vCleanSession("main.c / main : realloc() error", 0); goto _NewSession; } // Byte copy the screen into the buffer for fast compare memcpy(pBuffer, pRaster, iWidth * iHeight); } #endif // Preset framebuffer update message X and Y size to XDC_TILE mFBRMsg.r.w = mFBRMsg.r.h = XDC_TILE; // Release a key to the client socket so that child process can grab it if (-1 == (iDuplicateSocketKey = ReleaseCopyOfSocket(iClientSocket, UNIQUE_ID))) { vCleanSession("main.c / main : ReleaseCopyOfSocket() error", Errno()); goto _NewSession; } // Create incoming messages handling child process if (!CreateNewProcTags( NP_Entry, vProcessIncomes, NP_StackSize, 32000, NP_Name, "AmiVNC handler", TAG_DONE )) { vCleanSession("main.c / main : CreateNewProcTags() error", 0); goto _NewSession; } // Execute user command on accepted connection (if any) if (pPreStart) { char cCommand[128]; sprintf(cCommand, pPreStart, inet_ntoa(cliAddr.sin_addr)); SystemTags(cCommand, SYS_Asynch, TRUE, TAG_DONE); } // Session is truly opened now bSession = TRUE; // While not end of session (by child or by ourself) while (!bDie) { // Search for active screen change if (IntuitionBase -> FirstScreen != pActiveScreen) { if (bPlanar) // Original Amiga screens { // Check if new screen is also planar and has same dimensions if ((GetBitMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD) && (iWidth == GetBitMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, BMA_WIDTH)) // X size && (iHeight == GetBitMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, BMA_HEIGHT))) // Y size { // Grab new screen pActiveScreen = IntuitionBase -> FirstScreen; fprintf(fLog, "main.c / main : Screen set to [%s]\n", pActiveScreen -> Title); // Update depth iDepth = GetBitMapAttr(pActiveScreen -> RastPort.BitMap, BMA_DEPTH); // Depth is in Bits / pixel // Update CLUT (or CLUT8 if bVVA) jCnt = 1 << iDepth; if (bVVA) // BGR233 for (iCnt = 0 ; iCnt < jCnt ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); UBYTE wR = (lColor >> 9) & 0x07; UBYTE wG = (lColor >> 5) & 0x07; UBYTE wB = (lColor >> 2) & 0x03; CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR; } else // RGB16PC for (iCnt = 0 ; iCnt < jCnt ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); ULONG wR = (lColor >> 8) & 0x0f; ULONG wG = (lColor >> 4) & 0x0f; ULONG wB = (lColor >> 0) & 0x0f; CLUT[iCnt] = (wG << 4 | wB) << 8 | wR; } // Force client screen update (almost :-) memset(pBuffer, iWidth * iHeight, 0xFF); } else { vCleanSession("main.c / main : planar screenmode switch not allowed", 0); goto _NewSession; } } #ifndef PLANAR else // Chunky (RTG) { if (GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_ISCYBERGFX) && GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_ISLINEARMEM) && iWidth == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_WIDTH) && iHeight == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_HEIGHT) && iDepth == GetCyberMapAttr(IntuitionBase -> FirstScreen -> RastPort.BitMap, CYBRMATTR_BPPIX)) { // Grab new screen pActiveScreen = IntuitionBase -> FirstScreen; fprintf(fLog, "main.c / main : Screen set to [%s]\n", pActiveScreen -> Title); UnLockBitMap(LockBitMapTags(pActiveScreen -> RastPort.BitMap, LBMI_BASEADDRESS, (ULONG *) &uCnt, TAG_DONE)); pRaster = (UBYTE *) uCnt; // If depth == 1, update CLUT if (iDepth == 1) { if (bVVA) // BGR233 for (iCnt = 0 ; iCnt < 256 ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); UBYTE wR = (lColor >> 9) & 0x07; UBYTE wG = (lColor >> 5) & 0x07; UBYTE wB = (lColor >> 2) & 0x03; CLUT8[iCnt] = (wB << 3 | wG) << 3 | wR; } else // RGB16PC for (iCnt = 0 ; iCnt < 256 ; iCnt++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iCnt); ULONG wR = (lColor >> 8) & 0x0f; ULONG wG = (lColor >> 4) & 0x0f; ULONG wB = (lColor >> 0) & 0x0f; CLUT[iCnt] = (wG << 4 | wB) << 8 | wR; } // Force client screen update (almost :-) memset(pBuffer, iWidth * iHeight, 0xFF); } } else { vCleanSession("main.c / main : chunky screenmode switch not allowed", 0); goto _NewSession; } } #endif } // Search for changes in screen... for (jCnt = 0 ; jCnt < iHeight; jCnt += XDC_TILE) { for (iCnt = 0 ; iCnt < iWidth ; iCnt += XDC_TILE) { register int iYtile, iXtile; BOOL bChange = FALSE; #ifndef PLANAR if (!bPlanar) // chunky linear-addressed rasters for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) { if (memcmp((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth), (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth), XDC_TILE * iDepth)) { memcpy((UBYTE *) (pBuffer) + iDepth * (iCnt + (jCnt + iYtile) * iWidth), (UBYTE *) (pRaster) + iDepth * (iCnt + (jCnt + iYtile) * iWidth), XDC_TILE * iDepth); bChange = TRUE; } } else // planar rasters { #endif // 0 - Once every 10 scans, refresh palette (we have no event here to say palette has changed) if (!(iUpdate++ % 10)) { int nColor = 1 << iDepth, iColor; if (bVVA) for (iColor = 0 ; iColor < 256 ; iColor++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor); UBYTE wR = (lColor >> 9) & 0x07; UBYTE wG = (lColor >> 5) & 0x07; UBYTE wB = (lColor >> 2) & 0x03; CLUT8[iColor] = (wB << 3 | wG) << 3 | wR; } else for (iColor = 0 ; iColor < nColor ; iColor++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor); ULONG wR = (lColor >> 8) & 0x0f; ULONG wG = (lColor >> 4) & 0x0f; ULONG wB = (lColor >> 0) & 0x0f; CLUT[iColor] = (wG << 4 | wB) << 8 | wR; } } // 1 - get a chunky 32x32 1 byte clut entry buffer ReadPixelArray8(&(pActiveScreen -> RastPort), (unsigned long) iCnt, (unsigned long) jCnt, (unsigned long) iCnt + XDC_TILE - 1, (unsigned long) jCnt + XDC_TILE - 1, uCTile, &TempRP ); // 2 - then compare it to reference buffer. if !=, remember to update client and store new. for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) { if (memcmp((UBYTE *) (pBuffer) + (iCnt + (jCnt + iYtile) * iWidth), (UBYTE *) (uCTile) + (iYtile * XDC_TILE), XDC_TILE)) { memcpy((UBYTE *) (pBuffer) + (iCnt + (jCnt + iYtile) * iWidth), (UBYTE *) (uCTile) + (iYtile * XDC_TILE), XDC_TILE); bChange = TRUE; } } #ifndef PLANAR } #endif // If change found, send the tile if (bChange) { if (-1 == (send(iClientSocket, (UBYTE *) &mFBUpdMsg, sizeof(mFBUpdMsg), 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } mFBRMsg.r.x = iCnt; mFBRMsg.r.y = jCnt; // Send framebuffer update header if (-1 == (send(iClientSocket, (UBYTE *) &mFBRMsg, sizeof(mFBRMsg), 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } // Send update data if (bPlanar) { if (bVVA) { for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile++) uTile[iXtile + iYtile * XDC_TILE] = CLUT8[uCTile[iXtile + iYtile * XDC_TILE]]; // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } else { for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile++) *((UWORD *) (uTile + (iXtile + iYtile * XDC_TILE) * 2)) = CLUT[uCTile[iXtile + iYtile * XDC_TILE]]; // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } } #ifndef PLANAR else if ((!bVVA) && (bFastMode) && (iDepth == 2)) // 2 byte pixels under Pic96 : send directly from buffer (2 is idepth) { for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) memcpy(uTile + XDC_TILE * iYtile * iDepth, pRaster + iDepth * (iCnt + (jCnt + iYtile) * iWidth), XDC_TILE * iDepth); // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } else if ((!bVVA) && (iDepth == 1)) // RTG chunky 1 byte pixels { // Every 10 update, refresh color lookup table with 256 ready-to-send 16 bit RGB values if (!(iUpdate++ % 10)) { int iColor; for (iColor = 0 ; iColor < 256 ; iColor++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor); ULONG wR = (lColor >> 8) & 0x0f; ULONG wG = (lColor >> 4) & 0x0f; ULONG wB = (lColor >> 0) & 0x0f; CLUT[iColor] = (wG << 4 | wB) << 8 | wR; } } // Make up the RBG chunky buffer for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++) *((UWORD *) (uTile + (iXtile + iYtile * XDC_TILE) * 2)) = CLUT[pBuffer[iCnt + iXtile + (jCnt + iYtile) * iWidth]]; // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * 2, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } else // Dumb screenmode or VVA { if (iDepth > 1) { ReadPixelArray(uTile, // Buffer 0, 0, // Dest X/Y in buffer XDC_TILE * XDC_C_MAXDEPTH, &(pActiveScreen -> RastPort), iCnt, jCnt, // Source X/Y XDC_TILE, XDC_TILE, // Source w/h RECTFMT_ARGB ); if (bVVA) { // Make the BGR233 buffer into uTile for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++) { uTile[iXtile + iYtile * XDC_TILE] = (uTile[(iXtile + iYtile * XDC_TILE) * 4 + 1] & 0xE0) >> 5 | (uTile[(iXtile + iYtile * XDC_TILE) * 4 + 2] & 0xE0) >> 2 | (uTile[(iXtile + iYtile * XDC_TILE) * 4 + 3] & 0xC0) >> 0; } // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } else { // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE * XDC_C_MAXDEPTH, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } } else // iDepth == 1 and VVA (Depth == 1 and not VVA is trated above) { // Once every 10 scans, refresh palette (we have no event here to say palette has changed) if (!(iUpdate++ % 10)) { int iColor; for (iColor = 0 ; iColor < 256 ; iColor++) { ULONG lColor = GetRGB4(pActiveScreen -> ViewPort.ColorMap, (long) iColor); UBYTE wR = (lColor >> 9) & 0x07; UBYTE wG = (lColor >> 5) & 0x07; UBYTE wB = (lColor >> 2) & 0x03; CLUT8[iColor] = (wB << 3 | wG) << 3 | wR; } } // Make up the RBG chunky buffer for (iYtile = 0 ; iYtile < XDC_TILE ; iYtile ++) for (iXtile = 0 ; iXtile < XDC_TILE ; iXtile ++) uTile[iXtile + iYtile * XDC_TILE] = CLUT8[pBuffer[iCnt + iXtile + (jCnt + iYtile) * iWidth]]; // Send framebuffer update pixel data if (-1 == (send(iClientSocket, (UBYTE *) uTile, (LONG) XDC_TILE * XDC_TILE, 0))) { vCleanSession(XDC_SEND, Errno()); goto _NewSession; } } } #endif } } } } vCleanSession("main.c / main : Session stop (child stopped)", 0); goto _NewSession; }